import type { Scale, Progress, TaskRecord } from './types/progress';
import { STATUS_COLOR, PLAY_STATUS } from './types/progress';
import { Ref, ref, VNode, render, watch } from 'vue';
import { progressToTasksAndScales, getComponentsIds } from './utils/progressSimulation';
import { getFormatedToday } from './utils/date';
import { useBasicModel } from './useBasicModel';
import dayjs from 'dayjs';

export function useProgress(
  modelid: Ref<string | null>,
  viewTokenApi: Function,
  progressApi: Function,
  config?: any,
) {
  const highlightDefaultColor: string = '#25ac84';

  const originProgressData = ref<Progress[]>([]);
  const loading = ref<boolean>(true); // 数据是否正在加载
  const internalId = ref(); // 动画播放定时器ID
  const currentScale = ref<Scale>(); // 记录当前时间尺度
  const currentProgress = ref<number>(0); // 当前进度
  const playSpeed = ref<number>(100); // 播放速度，单位为ms/day
  const status = ref<PLAY_STATUS>('init') // 播放状态
  const tasks = ref<TaskRecord>({});
  const scales = ref<Scale[]>([]);

  const { elementid, viewer3D, drawable, model3D, resize } = useBasicModel(
    modelid,
    viewTokenApi,
  );

  // 监听模型变化，然后重新获取xml进度信息(因为xml信息由modelId指定)
  watch(
    () => modelid.value,
    (newValue) => {
      if (newValue) {
        loading.value = true;
        progressApi({ model_id: newValue })
          .then((res) => {
            originProgressData.value = res.rows;
            const data = progressToTasksAndScales(res.rows as Progress[]);
            tasks.value = data.tasks;
            scales.value = data.scales;
            currentScale.value = scales[0];
          })
          .catch((error) => {
            console.error(error);
          })
          .finally(() => {
            loading.value = false;
          })
      }
    },
    { immediate: true },
  );

  // 清除所有标签
  function clearAllDrawableItems() {
    drawable.value.clear();
  }

  // 
  /**
   * @abstract 在构件上添加默认的引线标签
   * @param componentId 标签所绑定的构件
   * @param text 标签文本
   * @param bgColor 标签背景颜色
   * @param height 标签的高度
   */
  function addLeadLabel(componentId: string, text: string, bgColor: string, height?: number): any {
    viewer3D.value.getModel().getComponentProperty(componentId, function (objectData) {
      const worldPosition = {
        x: (objectData.boundingBox.max.x + objectData.boundingBox.min.x) / 2,
        y: (objectData.boundingBox.max.y + objectData.boundingBox.min.y) / 2,
        z: (objectData.boundingBox.max.z + objectData.boundingBox.min.z) / 2,
      };
      let config = new window.Glodon.Bimface.Plugins.Drawable.LeadLabelConfig();
      config.offset = { x: 27, y: -47 };
      if (height) {
        config.height = height;
      }
      config.text = text;
      config.objectId = componentId;
      config.worldPosition = worldPosition;
      config.draggable = true;
      config.viewer = viewer3D.value;
      config.style = {
        backgroundColor: new window.Glodon.Web.Graphics.Color(bgColor, 1),
      };

      let label = new window.Glodon.Bimface.Plugins.Drawable.LeadLabel(config);

      drawable.value.addItem(label);
    });
  }

  /**
   * @abstract 在构件上添加自定义标签
   * @param componentId 标签所绑定的构件
   * @param vnode 标签所渲染的虚拟dom
   */
  function addCustomLabel(componentId: string, vnode: VNode) {
    viewer3D.value.getModel().getComponentProperty(componentId, function (objectData) {
      const worldPosition = {
        x: (objectData.boundingBox.max.x + objectData.boundingBox.min.x) / 2,
        y: (objectData.boundingBox.max.y + objectData.boundingBox.min.y) / 2,
        z: (objectData.boundingBox.max.z + objectData.boundingBox.min.z) / 2,
      };
      let config = new window.Glodon.Bimface.Plugins.Drawable.CustomItemConfig();
      const el = document.createElement('div');
      render(vnode, el);
      config.content = el;
      config.objectId = componentId;
      config.draggable = false;
      config.viewer = viewer3D;
      config.worldPosition = worldPosition;
      let label = new window.Glodon.Bimface.Plugins.Drawable.CustomItem(config);
      drawable.value.addItem(label);
    });
  }

  /**
   * @abstract 将镜头聚焦到多个构件
   * @param ids 所聚焦的构件们
   */
  function zoomToSelectedComponentsById(ids: string[]) {
    viewer3D.value.getModel().clearSelectedComponents();
    viewer3D.value.getModel().setSelectedComponentsById(ids);
    viewer3D.value.getModel().zoomToSelectedComponents();
    viewer3D.value.getModel().clearSelectedComponents();
  }

  /**
   * @abstract 高亮多个构件
   * @param ids 所高亮的构件们
   * @param color 高亮颜色 such as '#123456'
   */
  function highlightComponentsById(ids: string[], color?: string) {
    let highlightColor = new window.Glodon.Web.Graphics.Color(color ?? highlightDefaultColor, 1);
    model3D.value.opaqueComponentsById(ids);
    model3D.value.overrideComponentsColorById(ids, highlightColor);
    viewer3D.value.render();
  }

  /**
   * @abstract 将镜头拉回home视图
   */
  function backHomeView() {
    const customHomeView = viewer3D.value.getCustomHomeview();
    if (customHomeView) {
      viewer3D.value.setView(customHomeView);
    } else {
      const defaultHomeView = viewer3D.value.getDefaultHomeview();
      viewer3D.value.setView(defaultHomeView);
    }
  }

  /**
   * @abstract 渲染一个进度模拟时间尺度 
   * @param scale 所要渲染的时间尺度
   * @param ifRest 是否要重置（先半透明化所有组件）
   */
  function renderFrame(scale: Scale, ifRest = false) {

    currentScale.value = scale;

    if (ifRest) {
      restoreModel();
      model3D.value.transparentAllComponents();
    }

    /** 实体化在计划中已经完成的任务 */
    const doneComponentIds = getComponentsIds(scale.planTaksIds.done, tasks.value);
    model3D.value.opaqueComponentsById(doneComponentIds);

    /** 根据任务的计划完成率，高亮在计划中正在进行的任务 */
    scale.planTaksIds.doing.forEach((id) => {
      const task = tasks.value[id];

      const planProgress = scale.date.diff(task.startDate, 'day') / task.duration;
      const transparentValue = Math.min(Math.max(0, planProgress), 1);
      const componentIds = task.componentIds;

      model3D.value.opaqueComponentsById(componentIds);
      if (transparentValue < 1.0) {
        const color = new window.Glodon.Web.Graphics.Color(highlightDefaultColor, transparentValue);
        model3D.value.overrideComponentsColorById(componentIds, color);
      } else {
        model3D.value.restoreComponentsColorById(componentIds);
      }
      viewer3D.value.render();
    });
  }

  /**
   * @abstract 从指定的scale开始播放动画
   * @param msPerDay 
   * @returns 
   */
  function play() {

    let startScaleIdx;
    if (currentScale.value) {
      startScaleIdx = scales.value.findIndex((scale) => scale === currentScale.value);
    } else {
      startScaleIdx = 0;
    }

    if (startScaleIdx < 0 || startScaleIdx >= scales.value.length) {

      console.error(`无法从指定的日期开始播放进度动画`);
      status.value = 'init';
      return;
    }
    if (playSpeed.value < 0) {
      console.error(`播放动画的速度不能是负数`);
      status.value = 'init';
      return;
    }

    status.value = 'playing';

    restoreModel();
    model3D.value.transparentAllComponents();

    let scalesIdxPointer = startScaleIdx;
    const scalesLength = scales.value.length;

    internalId.value = setInterval(() => {
      const theScale: Scale = scales.value[scalesIdxPointer];

      renderFrame(theScale);

      currentScale.value = theScale;

      scalesIdxPointer++;
      if (scalesIdxPointer === scalesLength) {
        clearInterval(internalId.value);

        model3D.value.opaqueAllComponents();
        viewer3D.value.render();

        status.value = 'init';

      }

      updateProgress();
    }, playSpeed.value);
  }

  /**
   * @abstract 停止播放
   */
  function stop() {
    if (internalId) {
      clearInterval(internalId.value);
    }
    status.value = 'stopping';

    if (currentScale.value) {
      renderFrame(currentScale.value, true);
    }
  }

  /**
   * @abstract 设置进度条
   * @param scale 
   */
  function setCurrentScale(scale: Scale) {
    currentScale.value = scale;
    updateProgress();
    stop();
  }

  /**
   * @abstract 更新进度相关的信息
   */
  function updateProgress() {
    if (tasks.value && scales.value && currentScale) {
      const currentScaleIdx = scales.value.findIndex((scale) => scale === currentScale.value);
      const progress: number = ((currentScaleIdx + 1) / scales.value.length) * 100;
      currentProgress.value = progress;
    }
  }

  /**
   * @abstract 高亮指定任务的构件
   * @param taskId 所要高亮的任务id
   * @param label 所要渲染的引线标签
   */
  function highlightComponentsBySpecifyTask(
    taskId: string,
    label?: { text: string; color: string; height: number },
  ) {

    if (tasks.value[taskId]) {
      const task = tasks.value[taskId];

      if (label) {
        clearAllDrawableItems();
        addLeadLabel(task.componentIds[0], label.text, label.color, label.height);
      }

      viewer3D.value.getModel().clearSelectedComponents();
      viewer3D.value.getModel().setSelectedComponentsById(task.componentIds);
      viewer3D.value.getModel().zoomToSelectedComponents();

      model3D.value.transparentAllComponents(); // 透明化所有构件
      model3D.value.opaqueComponentsById(task.componentIds); // 实体化任务涉及的构件
      viewer3D.value.render();
      viewer3D.value.getModel().clearSelectedComponents();
    } else {
      console.warn(`所选任务与当前模型无关`);
    }
  }

  /** 重置模型 */
  function restoreModel() {
    model3D.value.restoreAllDefault();
    viewer3D.value.getModel().clearSelectedComponents();
    model3D.value.opaqueAllComponents();
    drawable.value.clear();
    viewer3D.value.render();
  }

  /**
   * @abstract 根据指定日期，展示未开始相关的任务信息
   * @param specifiedDate 指定的日期，默认为今天
   */
  function showSpecifyScaleTodoTasks(specifiedDate: dayjs.Dayjs = getFormatedToday()) {

    const scale: Scale | undefined = scales.value.find(item => item.date.isSame(specifiedDate));
    if (!scale) {
      console.error('在scales找不到对应的日期');
      return
    }

    interface ComponentIds {
      startLag: string[];
      startOnTime: string[];
    };

    let ids: ComponentIds = {
      startLag: getComponentsIds(scale.realTaskIds.startLag, tasks.value),
      startOnTime: getComponentsIds(scale.realTaskIds.startOnTime, tasks.value),
    };

    restoreModel();
    model3D.value.transparentAllComponents();

    highlightComponentsById(ids.startLag, STATUS_COLOR.START_LAG);
    highlightComponentsById(ids.startOnTime, STATUS_COLOR.START_ON_TIME);

    ids.startLag.length >= 0
      ? addLeadLabel(ids.startLag[0], '滞后开始', STATUS_COLOR.START_LAG)
      : undefined;
    ids.startOnTime.length >= 0
      ? addLeadLabel(ids.startOnTime[0], '预计按时开始', STATUS_COLOR.START_ON_TIME)
      : undefined;
  }

  /**
   * @abstract 根据指定日期，展示进行中的相关任务信息
   * @param specifiedDate 指定的日期，默认为今天
   */
  function showSpecifyScaleDoingTasks(specifiedDate: dayjs.Dayjs = getFormatedToday()) {

    const scale: Scale | undefined = scales.value.find(item => item.date.isSame(specifiedDate));
    if (!scale) {
      console.error('在scales找不到对应的日期');
      return
    }

    interface ComponentIds {
      doingNotStart: string[];
      doingAhead: string[];
      doingLag: string[];
    };

    const ids: ComponentIds = {
      doingNotStart: getComponentsIds(scale.realTaskIds.doingNotStart, tasks.value),
      doingAhead: getComponentsIds(scale.realTaskIds.doingAhead, tasks.value),
      doingLag: getComponentsIds(scale.realTaskIds.doingLag, tasks.value),
    };

    restoreModel();
    model3D.value.transparentAllComponents();

    highlightComponentsById(ids.doingNotStart, STATUS_COLOR.DOING_NOT_START);
    highlightComponentsById(ids.doingAhead, STATUS_COLOR.DOING_AHEAD);
    highlightComponentsById(ids.doingLag, STATUS_COLOR.DOING_LAG);

    ids.doingNotStart.length >= 0
      ? addLeadLabel(ids.doingNotStart[0], '仍未开始', STATUS_COLOR.DOING_NOT_START)
      : undefined;
    ids.doingAhead.length >= 0
      ? addLeadLabel(ids.doingAhead[0], '正常进行', STATUS_COLOR.DOING_AHEAD)
      : undefined;
    ids.doingLag.length >= 0
      ? addLeadLabel(ids.doingLag[0], '滞后进行', STATUS_COLOR.DOING_LAG)
      : undefined;
  }

  /**
   * @abstract 根据指定日期，展示已完成相关的任务信息
   * @param specifiedDate 指定的日期，默认为今天
   */
  function showSpecifyScaleDoneTasks(specifiedDate: dayjs.Dayjs = getFormatedToday()) {

    const scale: Scale | undefined = scales.value.find(item => item.date.isSame(specifiedDate));
    if (!scale) {
      console.error('在scales找不到对应的日期');
      return;
    }

    interface ComponentIds {
      done: string[];
      doneLag: string[];
    };

    let componentids: ComponentIds = {
      done: getComponentsIds(scale.realTaskIds.done, tasks.value),
      doneLag: getComponentsIds(scale.realTaskIds.doneLag, tasks.value),
    };

    restoreModel();
    model3D.value.transparentAllComponents();

    highlightComponentsById(componentids.doneLag, STATUS_COLOR.DONE_LAG);
    highlightComponentsById(componentids.done, STATUS_COLOR.DONE);

    componentids.done.length >= 0
      ? addLeadLabel(componentids.doneLag[0], '滞后完成', STATUS_COLOR.DONE_LAG)
      : undefined;
    componentids.doneLag.length >= 0
      ? addLeadLabel(componentids.done[0], '已完成', STATUS_COLOR.DONE)
      : undefined;
  }

  function resetSimulation() {
    clearInterval(internalId.value);
    restoreModel();
    status.value = 'init';
  }

  return {
    elementid,
    originProgressData,
    loading,
    tasks,
    scales,
    resize,
    setCurrentScale,
    addLeadLabel,
    addCustomLabel,
    backHomeView,
    highlightComponentsBySpecifyTask,
    method: {
      restoreModel,
    },

    controller: {
      data: {
        status,
        currentProgress,
        currentScale,
        playSpeed,
      },
      method: {
        play,
        stop,
        resetSimulation,
        renderFrame,
      }
    },

    status: {
      method: {
        showSpecifyScaleTodoTasks,
        showSpecifyScaleDoingTasks,
        showSpecifyScaleDoneTasks,
      }
    }
  };
}
